<template>
  <div class="table-toolbar">
    <!--顶部左侧区域-->
    <div class="flex items-center table-toolbar-left">
      <template v-if="title">
        <div class="table-toolbar-left-title">
          {{ title }}
          <n-tooltip v-if="titleTooltip" trigger="hover">
            <template #trigger>
              <n-icon class="ml-1 text-gray-400 cursor-pointer" size="18">
                <QuestionCircleOutlined />
              </n-icon>
            </template>
            {{ titleTooltip }}
          </n-tooltip>
        </div>
      </template>
      <slot name="tableTitle"></slot>
    </div>

    <div class="flex items-center table-toolbar-right">
      <!--顶部右侧区域-->
      <slot name="toolbar"></slot>
      <n-space item-style="display: flex;">
        <n-tooltip v-if="pageSpread" trigger="hover">
          <template #trigger>
            <n-checkbox v-model:checked="pageSpreadRowsRef.viewOnlySelected"
                        @change="onViewOnlySelectedEvent">
              只查看已选中<span>【{{ checkedRows.length }}】</span>条数据
            </n-checkbox>
          </template>
          <span>勾选后只查询选中数据</span>
        </n-tooltip>
        <n-tooltip trigger="hover">
          <template #trigger>
            <n-checkbox v-model:checked="pageSpread" label="跨页选中"
                        @change="onViewOnlySelectedEvent" />
          </template>
          <span>开启功能后可进行跨页勾选</span>
        </n-tooltip>
      </n-space>
      <!--刷新-->
      <n-tooltip trigger="hover">
        <template #trigger>
          <div class="table-toolbar-right-icon" @click="reSelectPageList">
            <n-icon size="18">
              <ReloadOutlined />
            </n-icon>
          </div>
        </template>
        <span>刷新</span>
      </n-tooltip>
      <!--密度-->
      <n-tooltip trigger="hover">
        <template #trigger>
          <div class="table-toolbar-right-icon">
            <n-dropdown
              v-model:value="tableSize"
              :options="densityOptions"
              trigger="click"
              @select="densitySelect"
            >
              <n-icon size="18">
                <ColumnHeightOutlined />
              </n-icon>
            </n-dropdown>
          </div>
        </template>
        <span>密度</span>
      </n-tooltip>
      <!--表格设置单独抽离成组件-->
      <ColumnSetting :tid="tid" />
    </div>
  </div>
  <div class="s-table">
    <n-data-table
      ref="tableElRef"
      v-bind="getBindValues"
      v-model:checked-row-keys="checkedRows"
      :bordered="false"
      :pagination="pagination"
      @update:page="updatePage"
      @update:page-size="updatePageSize"
      @update:sorter="handleSorterChange"
    >
      <template v-for="item in Object.keys($slots)" :key="item" #[item]="data">
        <slot v-bind="data" :name="item"></slot>
      </template>
    </n-data-table>
  </div>
</template>

<script lang="ts">
import {
  computed,
  defineComponent,
  nextTick,
  onMounted,
  reactive,
  ref,
  toRaw,
  toRefs,
  unref,
  watch
} from "vue";
import { ColumnHeightOutlined, QuestionCircleOutlined, ReloadOutlined } from "@vicons/antd";
import { createTableContext } from "./hooks/useTableContext";

import ColumnSetting from "./components/settings/ColumnSetting.vue";

import { useLoading } from "./hooks/useLoading";
import { useColumns } from "./hooks/useColumns";
import { useDataSource } from "./hooks/useDataSource";
import { usePagination } from "./hooks/usePagination";

import { basicProps } from "./props";

import { BasicTableProps } from "./types/table";

import { getViewportOffset } from "@/utils/domUtils";
import { useWindowSizeFn } from "@/hooks/event/useWindowSizeFn";
import { isBoolean } from "@/utils/is";
import { ComponentRef } from "/#/index";
import md5 from "js-md5";

const densityOptions = [
  {
    type: "menu",
    label: "紧凑",
    key: "small"
  },
  {
    type: "menu",
    label: "默认",
    key: "medium"
  },
  {
    type: "menu",
    label: "宽松",
    key: "large"
  }
];

export default defineComponent({
  components: {
    ReloadOutlined,
    ColumnHeightOutlined,
    ColumnSetting,
    QuestionCircleOutlined
  },
  props: {
    ...basicProps
  },
  emits: [
    "fetch-success",
    "fetch-error",
    "update:checked-row-keys",
    "edit-end",
    "edit-cancel",
    "edit-row-end",
    "edit-change"
  ],
  setup(props, { emit }) {
    const deviceHeight = ref(150);
    const tableElRef = ref<ComponentRef>(null);
    const wrapRef = ref<Nullable<HTMLDivElement>>(null);
    let paginationEl: HTMLElement | null;
    const checkedRows = ref(props.checkedRowKeys);
    console.log(checkedRows);
    const tableData = ref<Recordable[]>([]);
    const innerPropsRef = ref<Partial<BasicTableProps>>();

    const getProps = computed(() => {
      return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
    });
    let tid: string = unref(props).tid;
    if (tid == null || tid) {
      tid = md5(window.location.href);
    }
    const { getLoading, setLoading } = useLoading(getProps);

    const { getPaginationInfo, setPagination } = usePagination(getProps);
    const orderByObj = reactive({
      fixed: "",
      sort: ""
    });
    const orderByRef = ref(orderByObj);
    const pageSpreadRowsRef = ref(reactive({
      checkKeys: computed(() => {
        return [...checkedRows.value];
      }),
      viewOnlySelected: false
    }));
    const { getDataSourceRef, getDataSource, getRowKey, reload } = useDataSource(
      getProps,
      {
        getPaginationInfo,
        setPagination,
        tableData,
        setLoading,
        orderByRef,
        pageSpreadRowsRef
      },
      emit
    );

    const { getPageColumns, setColumns, getColumns, getCacheColumns, setCacheColumnsField } =
      useColumns(getProps);

    const state = reactive({
      tableSize: unref(getProps as any).size || "small",
      isColumnSetting: false
    });
    //跨页选中
    const pageSpread = ref(props.pageSpread);

    //页码切换
    function updatePage(page) {
      setPagination({ page: page });
      reSelectPageList();
    }

    //分页数量切换
    function updatePageSize(size) {
      setPagination({ page: 1, pageSize: size });
      reSelectPageList();
    }

    //密度切换
    function densitySelect(e) {
      state.tableSize = e;
    }

    //选中行
    function updateCheckedRowKeys(rowKeys) {
      emit("update:checked-row-keys", rowKeys);
    }

    function onViewOnlySelectedEvent(row) {
      updatePage(1);
      reSelectPageList();
    }

    //获取表格大小
    const getTableSize = computed(() => state.tableSize);

    //组装表格信息
    const getBindValues = computed(() => {
      const tableData = unref(getDataSourceRef);
      const maxHeight = tableData.length ? `${unref(deviceHeight)}px` : "auto";
      return {
        ...unref(getProps),
        loading: unref(getLoading),
        columns: toRaw(unref(getPageColumns)),
        rowKey: unref(getRowKey),
        data: tableData,
        size: unref(getTableSize),
        remote: true,
        "max-height": maxHeight
      };
    });
    //获取分页信息
    const pagination = computed(() => toRaw(unref(getPaginationInfo)));

    function setProps(props: Partial<BasicTableProps>) {
      innerPropsRef.value = { ...unref(innerPropsRef), ...props };
    }

    const tableAction = {
      reload,
      setColumns,
      setLoading,
      setProps,
      getColumns,
      getPageColumns,
      getCacheColumns,
      setCacheColumnsField,
      emit
    };

    const getCanResize = computed(() => {
      const { canResize } = unref(getProps);
      return canResize;
    });

    async function computeTableHeight() {
      const table = unref(tableElRef);
      if (!table) return;
      if (!unref(getCanResize)) return;
      const tableEl: any = table?.$el;
      const headEl = tableEl.querySelector(".n-data-table-thead ");
      const { bottomIncludeBody } = getViewportOffset(headEl);
      const headerH = 64;
      let paginationH = 2;
      let marginH = 24;
      if (!isBoolean(pagination)) {
        paginationEl = tableEl.querySelector(".n-data-table__pagination") as HTMLElement;
        if (paginationEl) {
          const offsetHeight = paginationEl.offsetHeight;
          paginationH += offsetHeight || 0;
        } else {
          paginationH += 28;
        }
      }
      let height =
        bottomIncludeBody - (headerH + paginationH + marginH + (props.resizeHeightOffset || 0));
      const maxHeight = props.maxHeight;
      height = maxHeight && maxHeight < height ? maxHeight : height;
      deviceHeight.value = height;
    }

    useWindowSizeFn(computeTableHeight, 280);

    onMounted(() => {
      nextTick(() => {
        computeTableHeight();
      });
    });
    watch(() => props.checkedRowKeys, () => {
      console.log("上级更新");
      checkedRows.value = props.checkedRowKeys;
    });
    watch(checkedRows, () => {
      console.log("更新上级");
      updateCheckedRowKeys(checkedRows.value);
    });
    createTableContext({ ...tableAction, wrapRef, getBindValues });
    const handleSorterChange = async (sorter: any) => {
      if (sorter.order) {
        orderByObj.sort = sorter.order == "ascend" ? "asc" : "desc";
        orderByObj.fixed = sorter.sorter;
      } else {
        orderByObj.sort = "";
        orderByObj.fixed = "";
      }
      reSelectPageList();
    };
    const resetPageReload = () => {
      updatePage(1);
      reSelectPageList();
    };
    let timer: any = null;
    //重新分页查询
    const reSelectPageList = () => {
      if (!pageSpread.value) {
        checkedRows.value = [];
      }
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => {
        reload();
        clearTimeout(timer);
      }, 100);
    };
    return {
      tid,
      orderByRef,
      pageSpread,
      checkedRows,
      onViewOnlySelectedEvent,
      resetPageReload,
      reSelectPageList,
      updateCheckedRowKeys,
      pageSpreadRowsRef,
      handleSorterChange,
      ...toRefs(state),
      tableElRef,
      getBindValues,
      getDataSource,
      densityOptions,
      reload: reSelectPageList,
      densitySelect,
      updatePage,
      updatePageSize,
      pagination,
      tableAction
    };
  }
});
</script>
<style lang="less" scoped>
.table-toolbar {
  display: flex;
  justify-content: space-between;
  padding: 0 0 16px 0;

  &-left {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex: 1;

    &-title {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      font-size: 16px;
      font-weight: 600;
    }
  }

  &-right {
    display: flex;
    justify-content: flex-end;
    flex: 1;

    &-icon {
      margin-left: 12px;
      font-size: 16px;
      cursor: pointer;
      color: var(--text-color);

      :hover {
        color: #1890ff;
      }
    }
  }
}

.table-toolbar-inner-popover-title {
  padding: 2px 0;
}
</style>
